package com.nanyang.tms.manager.waybill.shipment.handler.weight;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.nanyang.common.core.dict.CommonEnum;
import com.nanyang.common.core.domain.ApiResult;
import com.nanyang.common.core.flow.context.TransHandlerContext;
import com.nanyang.common.tool.utils.convert.BeanUtils;
import com.nanyang.sys.api.dto.response.dict.DictionaryResponse;
import com.nanyang.sys.api.service.dict.DictionaryRpcService;
import com.nanyang.tms.common.dict.TmsCalculateWeightEnum;
import com.nanyang.tms.common.dict.TmsExceptionEnum;
import com.nanyang.tms.common.exception.TmsManagerException;
import com.nanyang.tms.dao.product.ProductCarryRuleDao;
import com.nanyang.tms.dao.product.ProductWeightRuleDao;
import com.nanyang.tms.domain.cost.context.CalculateCostFreightContext;
import com.nanyang.tms.domain.product.ProductCarryRuleVO;
import com.nanyang.tms.domain.product.ProductWeightRuleVO;
import com.nanyang.tms.domain.waybill.shipment.context.CalculateSupplierWeightContext;
import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.NumberUtil;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class CalculateSupplierWeightByA extends AbstractCalculateSupplierWeight{
	private static final String CARGO_TYPE="CARGO_TYPE_CODE";
	private static final String C_EXPRESS="(length+width+height)*4";//周长公式
	private static final String V_EXPRESS="length*width*height";//体积公式
	private static final String VM_EXPRESS="(length*width*height)/factor";// 材积重公式
	private static final String CARRY_EXPRESS= "if (carryTypeCode == 'weight') " //进位计算公式
			 + "then "
			 +   "if( remainder > 0) "
			 +   "then "
			 +     "return quotient * carryRule + carryRule; "
			 +	" else "
			 +	   "return quotient * carryRule; "
			 + " if (carryTypeCode == 'round') "  
			 + " return round(totalChargeWeight,3); ";
	
    @Autowired
	private ProductWeightRuleDao productWeightRuleDao;
    @Autowired
    private ProductCarryRuleDao productCarryRuleDao;
    @Reference(version = "1.0.0", timeout = 10000, check = false)
	private DictionaryRpcService  dictionaryRpcService;
	@Override
	public String getCalculateType() {
		return TmsCalculateWeightEnum.PZZ.getTypeCode();
	}

	@Override
	public boolean generalProcess(TransHandlerContext context) {
		CalculateSupplierWeightContext calculateSupplierWeightContext=(CalculateSupplierWeightContext) context.getInnerContext(CalculateSupplierWeightContext.class);
		List<ProductWeightRuleVO> listWeightRuleByProductCode = productWeightRuleDao.listWeightRuleByProductCode(calculateSupplierWeightContext.getProductCode());
		if(CollUtil.isEmpty(listWeightRuleByProductCode)){
			throw new TmsManagerException(TmsExceptionEnum.WEIGHT_RULE_IS_NOT_EXIST.getCode(), TmsExceptionEnum.WEIGHT_RULE_IS_NOT_EXIST.getMessage());
		}
		//过滤货物类型 没有就返回错误
		List<ProductWeightRuleVO> firstFilterList=	listWeightRuleByProductCode.stream().filter(x -> calculateSupplierWeightContext.getCargoTypeCode().equals(x.getCargoTypeCode())).collect(Collectors.toList());
		if(CollUtil.isEmpty(firstFilterList)){
			throw new TmsManagerException(TmsExceptionEnum.WEIGHT_RULE_IS_NOT_EXIST.getCode(), TmsExceptionEnum.WEIGHT_RULE_IS_NOT_EXIST.getMessage());
		}
		//过滤 城市  如果没有设置城市，就取ALL
		List<ProductWeightRuleVO> secondFilterList =firstFilterList.stream().filter(x -> calculateSupplierWeightContext.getCityCode().equals(x.getCityCode())).collect(Collectors.toList());
		if(CollUtil.isEmpty(secondFilterList)){
			secondFilterList=firstFilterList.stream().filter(x -> x.getCityCode().equals("ALL")).collect(Collectors.toList());
		    if(CollUtil.isEmpty(secondFilterList)){
				throw new TmsManagerException(TmsExceptionEnum.WEIGHT_RULE_IS_NOT_EXIST.getCode(), TmsExceptionEnum.WEIGHT_RULE_IS_NOT_EXIST.getMessage());
		    }
		}
		//过滤 国家  如果没有设置国家，就取ALL
		List<ProductWeightRuleVO> thirdFilterList= secondFilterList.stream().filter(x -> calculateSupplierWeightContext.getCountyCode().equals(x.getCountyCode())).collect(Collectors.toList());
		if(CollUtil.isEmpty(thirdFilterList)){
			thirdFilterList=secondFilterList.stream().filter(x -> x.getCountyCode().equals("ALL")).collect(Collectors.toList());
			  if(CollUtil.isEmpty(thirdFilterList)){
					throw new TmsManagerException(TmsExceptionEnum.WEIGHT_RULE_IS_NOT_EXIST.getCode(), TmsExceptionEnum.WEIGHT_RULE_IS_NOT_EXIST.getMessage());
			    }
		}
		//设置材积系数
		BigDecimal volumeFactor=thirdFilterList.get(0).getVolumeFactor();
		//总实重
		BigDecimal gw=	calculateSupplierWeightContext.getCalculateSupplierWeightVolumeContext().stream().map(x -> x.getWeight()).reduce(BigDecimal.ZERO,BigDecimal::add);
		calculateSupplierWeightContext.setTotalWeight(gw);
		
		//总体积重
		BigDecimal vw=NumberUtil.div(calculateSupplierWeightContext.getCalculateSupplierWeightVolumeContext().stream().map(x -> {
			return NumberUtil.mul(x.getHeight(),x.getLength(),x.getWidth());
		}).reduce(BigDecimal.ZERO, BigDecimal::add),volumeFactor);
		calculateSupplierWeightContext.setTotalVolumeWeight(vw);
		
		//设置单件材积重、单件计费重、单件立方、单件周长、收货总件计费重、收货立方
		if(gw.compareTo(vw)<0){
			calculateSupplierWeightContext.getCalculateSupplierWeightVolumeContext().forEach(x -> {
				Map<String,Object> expressContext=BeanUtil.beanToMap(x);
				expressContext.put("factor", volumeFactor);
				x.setUnitVolume(this.runExpress(CalculateSupplierWeightByA.V_EXPRESS, expressContext));
				x.setUnitVolumeWeight(this.runExpress(CalculateSupplierWeightByA.VM_EXPRESS, expressContext));
				x.setGirth(this.runExpress(CalculateSupplierWeightByA.C_EXPRESS, expressContext));
				x.setUnitChargeWeight(x.getUnitVolumeWeight());
			});
		}
		else{
			calculateSupplierWeightContext.getCalculateSupplierWeightVolumeContext().forEach(x -> {
				Map<String,Object> expressContext=BeanUtil.beanToMap(x);
				expressContext.put("factor", volumeFactor);
				x.setUnitVolume(this.runExpress(CalculateSupplierWeightByA.V_EXPRESS, expressContext));
				x.setUnitVolumeWeight(this.runExpress(CalculateSupplierWeightByA.VM_EXPRESS, expressContext));
				x.setGirth(this.runExpress(CalculateSupplierWeightByA.C_EXPRESS, expressContext));
				x.setUnitChargeWeight(x.getWeight());
			});
		}
		//设置收货总件计费重
		BigDecimal totalPrieceChargeWeight=calculateSupplierWeightContext.getCalculateSupplierWeightVolumeContext().stream().map(x -> x.getUnitChargeWeight()).reduce(BigDecimal.ZERO,BigDecimal::add);
		calculateSupplierWeightContext.setTotalPrieceChargeWeight(totalPrieceChargeWeight);
		//设置收货立方
		BigDecimal receiptVolume=calculateSupplierWeightContext.getCalculateSupplierWeightVolumeContext().stream().map(x -> x.getUnitVolume()).reduce(BigDecimal.ZERO,BigDecimal::add);
		calculateSupplierWeightContext.setReceiptVolume(receiptVolume);
		//设置收货总计费重
		calculateSupplierWeightContext.setTotalChargeWeight(this.runExpress(thirdFilterList.get(0).getWeightExpression(), BeanUtil.beanToMap(calculateSupplierWeightContext)));
		
		ProductCarryRuleVO carryRule = productCarryRuleDao.getCarryRule(calculateSupplierWeightContext.getProductCode(), calculateSupplierWeightContext.getTotalChargeWeight());
		   if(carryRule==null){
			   throw new TmsManagerException(TmsExceptionEnum.CARRY_RULE_IS_NOT_EXIST.getCode(), TmsExceptionEnum.CARRY_RULE_IS_NOT_EXIST.getMessage());
		   }
		 //重量进位计算
		   calculateSupplierWeightContext.setCarryRule(carryRule.getCarryValue());
		   calculateSupplierWeightContext.setCarryTypeCode(carryRule.getCarryTypeCode());
		Map<String,Object> expressContext=BeanUtil.beanToMap(calculateSupplierWeightContext);
		calculateSupplierWeightContext.setTotalChargeWeight(this.runExpress(CalculateSupplierWeightByA.CARRY_EXPRESS, expressContext));
		
		//此context 向下传递到下一个通用context
		try {
			CalculateCostFreightContext calculateCostFreightContext=(CalculateCostFreightContext) context.getInnerContext(CalculateCostFreightContext.class);
			BeanUtils.copyProperties(calculateSupplierWeightContext, calculateCostFreightContext);
		} catch (Exception e) {
			log.warn("calculateCostFreightContext is not setted,please check calculateCostFreightContext whether or not need set!");
		}
		return true;
	}
	
	@SuppressWarnings("unused")
	private BigDecimal runExpress(String express,Map<String, Object> context){
		ExpressRunner runner = new ExpressRunner(true,false);
		try {
			DefaultContext<String, Object> defaultContext = new DefaultContext<String, Object>();
			context.entrySet().stream().forEach(x->defaultContext.put(x.getKey(), x.getValue()));
			Object r = runner.execute(express, defaultContext, null, true, false);
			return Convert.toBigDecimal(r) ;
		} catch (Exception e) {
			throw new TmsManagerException(CommonEnum.SYSTEM_EXCEPTION.getMessage(),e);
		}
		
	}
	private void processBigDecimal(Map<String,Object> map){
		map.entrySet().stream().forEach(x -> {
			if (x.getValue() instanceof BigDecimal){
				  x.setValue(((BigDecimal)x.getValue()).setScale(0, BigDecimal.ROUND_UP).longValue());
			}
		});
	}
	public static void main(String[] args) throws Exception {
//		String carry=  "remainder * carryValue";
		String carry=  ""
				+"if (carryTypeCode == 'weight') "
			 + "then "
			 +   "if( remainder > 0) "
			 +   "then "
			 +     "return quotient * carryValue + carryValue; "
			 +	" else "
			 +	   "return quotient * carryValue; "
			 + " if (carryTypeCode == 'round') "  
			 + " return round(totalChargeWeight,3); ";
		
		
		String template ="if (totalWeight>totalVolumeWeight) then return totalWeight else return (totalVolumeWeight-totalWeight)*0.5+totalWeight";
		ExpressRunner runner = new ExpressRunner(true,false);
		DefaultContext<String, Object> context = new DefaultContext<String, Object>();
		context.put("carryTypeCode","weight" );
		context.put("totalChargeWeight", new BigDecimal("12.1789"));
		context.put("quotient", new BigDecimal("2"));
		context.put("carryValue",new BigDecimal("5.67"));
		context.put("remainder",new BigDecimal("5.67"));
		String express = "round(gw,3)";
		Object r = runner.execute(carry, context, null, true, false);
		System.out.println(Convert.toBigDecimal(r) );
    }
}
